// RegAllocator.h
// A general registers allocator for all translators

#ifndef REGALLOCATOR_H
#define REGALLOCATOR_H

#include "crossbit/common.h"
#include "crossbit/UTIL.h"

namespace crossbit { 

    enum RegAccessMode
    {
        USE = 0,
        DEF
    };

    class VBlock; 

    class RegAllocator{
        public:
            // callback of regSpillIn and regSpillOut, provided for corresponding translators
            typedef void (* CBOfSpillIn) (XTMemAddr mem, XTRegNum treg);
            typedef void (* CBOfSpillOut)(XTRegNum treg, XTMemAddr mem); 

            // reg_to_reg
            typedef void (* CBOfRegToReg) (XTRegNum reg1, XTRegNum reg2);
        public:
            // when different translators initialize the reg allocator, they should specify their own
            // callback pointers for the reg allocator
            RegAllocator( XTUint8 num_regs, CBOfSpillIn cb_spill_in, CBOfSpillOut cb_spill_out, CBOfRegToReg cb_regtoreg )
            { 
                ra_num_of_reg = num_regs;
                ra_cb_spill_in = cb_spill_in;
                ra_cb_spill_out = cb_spill_out;
                ra_cb_reg_to_reg = cb_regtoreg;

                // initialize the vinst seq
                vinst_seq = 0;
                ra_spill_pool = (XTInt32 *)UTIL::XTMalloc(600 * ra_num_of_reg * sizeof(XTInt32));
                UTIL::XTMemset((void *)ra_spill_pool, 0, 600 * ra_num_of_reg * sizeof(XTInt32));
            }

            virtual ~RegAllocator()
            {
                if (ra_spill_pool)
                    UTIL::XTFree(ra_spill_pool);
            }
            // allocate any physical register for a virtual register, whose access mode is <code>mode</code>
            virtual XTRegNum regAlloc(XTRegNum vreg, RegAccessMode mode) = 0;	        
            // forcing allocate <code>expect</code> register for the virtual register
            virtual XTRegNum regAllocForce(XTRegNum vreg, XTRegNum expect, RegAccessMode mode) = 0;
            // added by suntingtao on 2009-03-07
            // reg_mask : the expect registers , if reg_mask & ( 1 << X86::EAX  ) == true , the EAX is one of the expect registers
            virtual XTRegNum regAllocExpect(XTRegNum vreg, XTUint8 reg_mask, RegAccessMode mode){
                assert(0 && "it should be implemented\n");
                return (XTRegNum)-1;
            }
            // allocate a physical register except the <code>except</code> for the virtual register
            virtual XTRegNum regAllocForceExcept(XTRegNum vreg, XTRegNum except, RegAccessMode mode) = 0;
            // the physical register <code>reg</code> is reserved , it could not be allocated 
            virtual void regAllocReserve(XTRegNum reg) = 0;
            // release a reserved physical register
            virtual void regAllocRelease(XTRegNum reg) = 0;
            // initial the registers 
            virtual void init(VBlock *vb) = 0;

            //for some trivial stuffs
            virtual void phaseTask()
            {}

            // In Reg allocator, we should maintain a vinst sequence to record the current VInst which are being encoding.
            virtual void incrementVinstSeq()
            {
                ++vinst_seq;
            }

        protected:
            // the index of the to current <code>VInst</code> in the <code>VBlock</code>
            XTInt32 vinst_seq;
            // the number of the physical registers could be allocated
            XTRegNum ra_num_of_reg;
            // a pointer to the spill pool, used to stored the content of a spilled physical register
            XTInt32 *ra_spill_pool;
            // the call back functions
            CBOfSpillIn ra_cb_spill_in;
            CBOfSpillOut ra_cb_spill_out;		
            CBOfRegToReg ra_cb_reg_to_reg;

            virtual void regSpillIn(XTRegNum vreg, XTRegNum treg)
            {
                (*ra_cb_spill_in)((XTMemAddr)(ra_spill_pool+vreg), treg);
            }

            // Spill out the allocated target reg for the vreg
            virtual XTRegNum regSpillOut(XTRegNum vreg) = 0;

            // ========================================
            // virtual registers status
            // ========================================
            const static XTInt32 UNMAPPED       = 0x01;
            const static XTInt32 MAPPED         = 0x02;
            // already mapped but have been spilled into memory
            const static XTInt32 SPILLED 		= 0x04;

            // ========================================
            // target register status
            // ========================================
            const static XTInt32 FREE			= 0x01;
            const static XTInt32 ALLOCATED		= 0x02;
            const static XTInt32 RESERVED		= 0x04;

            // ========================================
            // this struct is used by physical registers to  
            // record the regs' information which are now
            // under use.
            // ========================================
            struct RegUsage {
                XTInt32 status;         // the status of the physical register 
                XTRegNum mapped_to;		// mapped virtual register
                XTUint32	inst;		// the num of the instruction belonged to
            };


    };

}

#endif
